package com.yzc.android.utils;

import android.os.Environment;
import android.text.TextUtils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import com.orhanobut.logger.LogLevel;
import com.orhanobut.logger.Logger;
import com.orhanobut.logger.Printer;
import com.yzc.android.BuildConfig;

/**
 * Created by yzc on 16/4/21.
 */
public class LogUtils {
    private static String appTag = "logger";

    static {
        initCLog();
        init();
    }

    public static void init() {
        // init com.orhanobut.logger.Logger
        if (BuildConfig.CURRENT_CONTEXT_MODE_TEST) {
            Logger.init(appTag).methodCount(0).methodOffset(0).logLevel(LogLevel.FULL);
        }
        else
        {
            Logger.init(appTag).logLevel(LogLevel.NONE);
        }
    }

    private static void initCLog() {
        // init CLog
        if (BuildConfig.CURRENT_CONTEXT_MODE_TEST) {
            CLog.setLogLevel(CLog.LEVEL_VERBOSE);
        }
        else if (BuildConfig.CURRENT_CONTEXT_MODE_PRE_PRODUCT)
        {
            CLog.setLogLevel(CLog.LEVEL_WARNING);
        }
        else if (BuildConfig.CURRENT_CONTEXT_MODE_ONLINE)
        {
            CLog.setLogLevel(CLog.LEVEL_ERROR);
        }
    }

    private static String generateTag() {
        StackTraceElement caller = new Throwable().getStackTrace()[2];
        String tag = "%s.%s(L:%d)";
        String callerClazzName = caller.getClassName();
        callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
        tag = String.format(Locale.getDefault(), tag, callerClazzName, caller.getMethodName(), caller.getLineNumber());
        tag = TextUtils.isEmpty(appTag) ? tag : appTag + ":" + tag;
        return tag;
    }

    private static String detailTag()
    {
        StackTraceElement caller = new Throwable().getStackTrace()[2];
        String tag = "%s:%s.%s(L:%d)";
        String callerClazzName = caller.getClassName();
        callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
        tag = String.format(Locale.getDefault(), tag, getCurrentDateTime(), callerClazzName, caller.getMethodName(), caller.getLineNumber());
        return tag;
    }

    private static String simpleTag()
    {
        String tag = "%s";
        tag = String.format(Locale.getDefault(), tag, getCurrentDateTime());
        return tag;
    }

    public static Printer t(String tag) {
        return Logger.t(tag);
    }

    public static void v(final String tag, String msg, Object... args) {
        CLog.v(tag, msg, args);
    }

    public static void v(String msg, Object... args) {
        CLog.v(generateTag(), msg, args);
    }

    public static void vLocal(final String tag, String msg, Object... args) {
        asyncWriteDebugLog(tag, tag + ": " + String.format(msg, args), false);
        CLog.v(tag, msg, args);
    }

    public static void vLocal(String msg, Object... args) {
        asyncWriteDebugLog(null, generateTag() + ": " + String.format(msg, args), false);
        CLog.v(generateTag(), msg, args);
    }

    public static void vUpload(final String tag, String msg, Object... args) {
        asyncWriteDebugLog(tag, tag + ": " + String.format(msg, args), true);
        CLog.v(tag, msg, args);
    }

    public static void vUpload(String msg, Object... args) {
        asyncWriteDebugLog(null, generateTag() + ": " + String.format(msg, args), true);
        CLog.v(generateTag(), msg, args);
    }

    public static void d(String tag, String msg, Object... args) {
        CLog.d(tag, msg, args);
    }

    public static void d(String msg, Object... args) {
        CLog.d(generateTag(), msg, args);
    }

    public static void local(final String tag, String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s:%s: %s", simpleTag(), tag, String.format(msg, args));
        asyncWriteDebugLog(tag, formatLog, false);
        CLog.d(tag, msg, args);
    }

    public static void local(String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s: %s", simpleTag(), String.format(msg, args));
        asyncWriteDebugLog(null, formatLog, false);
        CLog.d(generateTag(), msg, args);
    }

    public static void upload(final String tag, String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s:%s: %s", simpleTag(), tag, String.format(msg, args));
        asyncWriteDebugLog(tag, formatLog, true);
        CLog.d(tag, msg, args);
    }

    public static void upload(String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s: %s", simpleTag(), String.format(msg, args));
        asyncWriteDebugLog(null, formatLog, true);
        CLog.d(generateTag(), msg, args);
    }

    public static void i(String tag, String msg, Object... args) {
        CLog.i(tag, msg, args);
    }

    public static void i(String msg, Object... args) {
        CLog.i(generateTag(), msg, args);
    }

    public static void w(String tag, String msg, Object... args) {
        CLog.w(tag, msg, args);
    }

    public static void w(String msg, Object... args) {
        CLog.w(generateTag(), msg, args);
    }

    public static void e(String tag, String msg, Object... args) {
        CLog.e(tag, msg, args);
    }

    public static void e(String msg, Object... args) {
        CLog.e(generateTag(), msg, args);
    }

    public static void e(String tag, Throwable throwable, String msg, Object... args) {
        if(throwable != null && msg != null) {
            msg = msg + " : " + throwable.toString();
        }

        if(throwable != null && msg == null) {
            msg = throwable.toString();
        }

        if(msg == null) {
            msg = "No msg/exception is set";
        }
        e(tag, msg, args);
    }

    public static void e(Throwable throwable, String msg, Object... args) {
        if(throwable != null && msg != null) {
            msg = msg + " : " + throwable.toString();
        }

        if(throwable != null && msg == null) {
            msg = throwable.toString();
        }

        if(msg == null) {
            msg = "No msg/exception is set";
        }
        e(generateTag(), msg, args);
    }

    public static void eLocal(final String tag, String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s:%s: %s", detailTag(), tag, String.format(msg, args));
        asyncWriteExceptionLog(formatLog);
        CLog.e(tag, msg, args);
    }

    public static void eLocal(String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s: %s", detailTag(), String.format(msg, args));
        asyncWriteExceptionLog(formatLog);
        CLog.e(generateTag(), msg, args);
    }

    public static void eLocal(String tag, Throwable throwable, String msg, Object... args) {
        if(throwable != null && msg != null) {
            msg = msg + " : " + throwable.toString();
        }

        if(throwable != null && msg == null) {
            msg = throwable.toString();
        }

        if(msg == null) {
            msg = "No msg/exception is set";
        }
        eLocal(tag, msg, args);
    }

    public static void eLocal(Throwable throwable, String msg, Object... args) {
        if(throwable != null && msg != null) {
            msg = msg + " : " + throwable.toString();
        }

        if(throwable != null && msg == null) {
            msg = throwable.toString();
        }

        if(msg == null) {
            msg = "No msg/exception is set";
        }
        eLocal(generateTag(), msg, args);
    }


    public static void eUpload(final String tag, String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s:%s: %s", detailTag(), tag, String.format(msg, args));
        asyncWriteDebugLog(tag, formatLog, true);
        CLog.e(tag, msg, args);
    }

    public static void eUpload(String msg, Object... args) {
        final String formatLog = String.format(Locale.getDefault(), "%s: %s", detailTag(), String.format(msg, args));
        asyncWriteDebugLog(null, formatLog, true);
        CLog.e(generateTag(), msg, args);
    }

    public static void eUpload(String tag, Throwable throwable, String msg, Object... args) {
        if(throwable != null && msg != null) {
            msg = msg + " : " + throwable.toString();
        }

        if(throwable != null && msg == null) {
            msg = throwable.toString();
        }

        if(msg == null) {
            msg = "No msg/exception is set";
        }
        eUpload(tag, msg, args);
    }

    public static void eUpload(Throwable throwable, String msg, Object... args) {
        if(throwable != null && msg != null) {
            msg = msg + " : " + throwable.toString();
        }

        if(throwable != null && msg == null) {
            msg = throwable.toString();
        }

        if(msg == null) {
            msg = "No msg/exception is set";
        }
        eUpload(generateTag(), msg, args);
    }


    public static void wtf(String tag, String msg, Object... args) {
        CLog.f(tag, msg, args);
    }

    public static void wtf(String msg, Object... args) {
        CLog.f(generateTag(), msg, args);
    }

    // 以下为log保存到本地
    /**
     * 默认文件夹
     */
    public static final String LOCAL_DEBUG_LOG_FOLDER = Environment.getExternalStorageDirectory().getAbsolutePath() + "/KDCommon/Local/Debug/";

    public static final String LOCAL_ERROR_LOG_FOLDER = Environment.getExternalStorageDirectory().getAbsolutePath() + "/KDCommon/Local/Error/";

    public static final String UPLOAD_LOG_FOLDER = Environment.getExternalStorageDirectory().getAbsolutePath() + "/KDCommon/Upload/";

    private static void asyncWriteDebugLog(final String tag, final String log, final boolean needUpload) {
        String folderPath = needUpload ? UPLOAD_LOG_FOLDER : LOCAL_DEBUG_LOG_FOLDER;
        final String fileFullPath = needUpload ? folderPath+generateFileName(tag) : folderPath+generateFileName(tag);
        ThreadPoolManager.getInstance().execute(new Runnable() {
            @Override
            public void run() {
                FileUtils.writeFile(fileFullPath, log, true);
            }
        });
    }

    private static void asyncWriteExceptionLog(final String log) {
        final String fileFullPath = LOCAL_ERROR_LOG_FOLDER+generateFileName(null);
        ThreadPoolManager.getInstance().execute(new Runnable() {
            @Override
            public void run() {
                FileUtils.writeFile(fileFullPath, log, true);
            }
        });
    }

    public static String generateFileName(final String tag)
    {
        String result = "log_";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
        result += dateFormat.format(new Date());
        if (!TextUtils.isEmpty(tag)) {
            result += "_";
            result += tag;
        }
        result += ".txt";
        return result;
    }

    public static String generateFileZipName(final String tag)
    {
        String result = "log_";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
        result += dateFormat.format(new Date());
        if (!TextUtils.isEmpty(tag)) {
            result += "_";
            result += tag;
        }
        result += ".zip";
        return result;
    }

    private static String getCurrentDateTime()
    {
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.FULL, Locale.getDefault());
        return df.format(new Date());
    }
}
